package order

import (
	"context"
	"strconv"
	"strings"
	"time"

	"mall/common/globalkey"
	"mall/common/moneyx"
	"mall/common/resultx"
	"mall/service/order/model"
	"mall/service/order/rpc/internal/svc"
	"mall/service/order/rpc/types/order"

	"github.com/volatiletech/null/v8"
	"github.com/zeromicro/go-zero/core/logx"
)

type CreateOrderLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
	logx.Logger
}

func NewCreateOrderLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateOrderLogic {
	return &CreateOrderLogic{
		ctx:    ctx,
		svcCtx: svcCtx,
		Logger: logx.WithContext(ctx),
	}
}

func (l *CreateOrderLogic) CreateOrder(in *order.OrderInfo) (*order.CreateOrderResp, error) {
	if in.Sn == nil || len(*in.Sn) == 0 {
		return nil, resultx.StatusError(resultx.ORDER_SN_REQUIRED, "")
	}

	if in.UserId == nil || *in.UserId == 0 {
		return nil, resultx.StatusError(resultx.USER_ID_REQUIRED, "")
	}

	if len(in.Skus) == 0 {
		return nil, resultx.StatusError(resultx.PRODUCT_VARIATION_ID_REQUIRED, "")
	}

	filterMap := make(map[string]map[string][]any)
	filterMap[model.OrderColumns.OrderSN] = map[string][]any{
		"equalTo": []any{*in.Sn},
	}
	_, count, err := l.svcCtx.Order.GetList(l.ctx, model.M{
		"pageSize": uint64(1),
		"select":   ",",
	}, 0, filterMap)
	if err != nil {
		return nil, err
	}

	if count > 0 {
		return nil, resultx.StatusError(resultx.ORDER_SN_EXISTS, "")
	}

	tx, err := l.svcCtx.DB.BeginTx(l.ctx, nil)
	if err != nil {
		return nil, resultx.StatusError(resultx.ORDER_CREATE_FAILED, "")
	}

	var trade model.Order
	trade.UserID = *in.UserId
	if in.UserRank != nil {
		trade.UserRank = *in.UserRank
	}
	if in.Buyer != nil {
		trade.Buyer = *in.Buyer
	}
	trade.OrderSN = *in.Sn
	if in.OrderType != nil {
		trade.OrderType = uint8(*in.OrderType)
	}
	if in.SourceType != nil {
		trade.SourceType = uint8(*in.SourceType)
	}
	if in.Number != nil {
		trade.Quantity = uint16(*in.Number)
	}
	if in.GemAmount != nil && len(strings.TrimSpace(*in.GemAmount)) > 0 {
		if gem, err := moneyx.ParseGem(strings.TrimSpace(*in.GemAmount)); err != nil {
			logx.Errorw("CreateOrder GemAmount failed to ParseGem", logx.Field("detail", err.Error()))
		} else {
			trade.GemAmount = uint64(gem)
		}
	}
	if in.RetailAmount != nil && len(*in.RetailAmount) > 0 {
		if val, err := moneyx.ParseAmount(*in.RetailAmount); err != nil {
			logx.Errorw("CreateOrder RetailAmount failed to ParseAmount", logx.Field("detail", err.Error()))
		} else {
			trade.RetailAmount = uint64(val)
		}
	}
	if in.Freight != nil && len(*in.Freight) > 0 {
		if val, err := moneyx.ParseAmount(*in.Freight); err != nil {
			logx.Errorw("CreateOrder Freight failed to ParseAmount", logx.Field("detail", err.Error()))
		} else {
			trade.Freight = uint64(val)
		}
	}
	if in.DiscountAmount != nil && len(*in.DiscountAmount) > 0 {
		if val, err := moneyx.ParseAmount(*in.DiscountAmount); err != nil {
			logx.Errorw("CreateOrder DiscountAmount failed to ParseAmount", logx.Field("detail", err.Error()))
		} else {
			trade.DiscountAmount = uint64(val)
		}
	}
	if in.AdjustAmount != nil && len(*in.AdjustAmount) > 0 {
		if val, err := moneyx.ParseAmount(*in.AdjustAmount); err != nil {
			logx.Errorw("CreateOrder AdjustAmount failed to ParseAmount", logx.Field("detail", err.Error()))
		} else {
			trade.AdjustAmount = int64(val)
		}
	}
	if in.ActualAmount != nil && len(*in.ActualAmount) > 0 {
		if val, err := moneyx.ParseAmount(*in.ActualAmount); err != nil {
			logx.Errorw("CreateOrder ActualAmount failed to ParseAmount", logx.Field("detail", err.Error()))
		} else {
			trade.ActualAmount = uint64(val)
		}
	}
	if in.DepositAmount != nil && len(*in.DepositAmount) > 0 {
		if val, err := moneyx.ParseAmount(*in.DepositAmount); err != nil {
			logx.Errorw("CreateOrder DepositAmount failed to ParseAmount", logx.Field("detail", err.Error()))
		} else {
			trade.DepositAmount = uint64(val)
		}
	}
	if in.BalanceAmount != nil && len(*in.BalanceAmount) > 0 {
		if val, err := moneyx.ParseAmount(*in.BalanceAmount); err != nil {
			logx.Errorw("CreateOrder BalanceAmount failed to ParseAmount", logx.Field("detail", err.Error()))
		} else {
			trade.BalanceAmount = uint64(val)
		}
	}
	if in.RemainingAmount != nil && len(*in.RemainingAmount) > 0 {
		if val, err := moneyx.ParseAmount(*in.RemainingAmount); err != nil {
			logx.Errorw("CreateOrder RemainingAmount failed to ParseAmount", logx.Field("detail", err.Error()))
		} else {
			trade.RemainingAmount = uint64(val)
		}
	}
	if in.Gems != nil && *in.Gems > 0 {
		trade.Gems = *in.Gems
	}
	var tradeState uint16
	if in.TradeState != nil && *in.TradeState > 0 {
		tradeState = uint16(*in.TradeState)
		trade.TradeState = tradeState
	}
	if in.Remark != nil && len(*in.Remark) > 0 {
		trade.Remark = *in.Remark
	}
	if in.SellerMemo != nil && len(*in.SellerMemo) > 0 {
		trade.SellerMemo = *in.SellerMemo
	}
	if in.AutoComfirmDays != nil && *in.AutoComfirmDays > 0 {
		trade.AutoComfirmDays = uint8(*in.AutoComfirmDays)
	}
	now := time.Now()
	trade.CreatedAt = now
	trade.UpdatedAt = now

	rel := &model.OrderRel{}
	if len(in.Skus) > 0 {
		for _, v := range in.Skus {
			var orderItem model.OrderItem
			if v.ProductCode != nil && len(strings.TrimSpace(*v.ProductCode)) > 0 {
				orderItem.ProductCode = *v.ProductCode
			}
			if v.SkuId != nil && *v.SkuId > 0 {
				orderItem.SkuID = *v.SkuId
			}
			if v.SkuCode != nil && len(strings.TrimSpace(*v.SkuCode)) > 0 {
				orderItem.SkuCode = *v.SkuCode
			}
			if v.Sku != nil && len(*v.Sku) > 0 {
				orderItem.Sku = *v.Sku
			}
			if v.ImageId != nil && len(*v.ImageId) > 0 {
				if i, err := strconv.ParseInt(*v.ImageId, 10, 64); err == nil {
					orderItem.SkuImageID = uint64(i)
				}
			}
			if v.ImageUrl != nil && len(*v.ImageUrl) > 0 {
				orderItem.SkuImageURL = *v.ImageUrl
			}
			if v.ProductId != nil && *v.ProductId > 0 {
				orderItem.ProductID = *v.ProductId
			}
			if v.PostId != nil && *v.PostId > 0 {
				orderItem.PostID = *v.PostId
			}
			if v.InviterId != nil && *v.InviterId > 0 {
				orderItem.InviterID = *v.InviterId
			}
			if v.EntryId != nil && *v.EntryId > 0 {
				orderItem.EntryID = *v.EntryId
			}
			if v.Title != nil && len(*v.Title) > 0 {
				orderItem.Title = *v.Title
			}
			if v.Slug != nil && len(*v.Slug) > 0 {
				orderItem.Slug = *v.Slug
			}
			if v.ProductType != nil && *v.ProductType > 0 {
				orderItem.ProductType = uint8(*v.ProductType)
			}
			if v.BrandId != nil && *v.BrandId > 0 {
				orderItem.BrandID = *v.BrandId
			}
			if v.BrandTitle != nil && len(*v.BrandTitle) > 0 {
				orderItem.BrandTitle = *v.BrandTitle
			}
			if v.BrandSlug != nil && len(*v.BrandSlug) > 0 {
				orderItem.BrandSlug = *v.BrandSlug
			}
			if v.GemPrice != nil && len(*v.GemPrice) > 0 {
				if gem, err := moneyx.ParseGem(*v.GemPrice); err != nil {
					logx.Errorw("CreateOrder OrderItem GemPrice failed to ParseGem", logx.Field("detail", err.Error()))
				} else {
					orderItem.GemPrice = uint64(gem)
				}
			}
			if v.RetailPrice != nil && len(*v.RetailPrice) > 0 {
				if val, err := moneyx.ParseAmount(*v.RetailPrice); err != nil {
					logx.Errorw("CreateOrder OrderItem RetailPrice failed to ParseAmount", logx.Field("detail", err.Error()))
				} else {
					orderItem.RetailPrice = uint64(val)
				}
			}
			if v.Quantity != nil && *v.Quantity > 0 {
				orderItem.Quantity = uint(*v.Quantity)
			}
			if v.Weight != nil && len(*v.Weight) > 0 {
				if val, err := moneyx.ParseWeight(*v.Weight); err != nil {
					logx.Errorw("CreateOrder OrderItem Weight failed to ParseWeight", logx.Field("detail", err.Error()))
				} else {
					orderItem.Weight = uint(val)
				}
			}
			orderItem.TradeState = tradeState
			orderItem.Status = uint8(globalkey.StatusEnabled)
			if v.GemAmount != nil && len(*v.GemAmount) > 0 {
				if gem, err := moneyx.ParseGem(*v.GemAmount); err != nil {
					logx.Errorw("CreateOrder OrderItem GemAmount failed to ParseGem", logx.Field("detail", err.Error()))
				} else {
					orderItem.GemAmount = uint64(gem)
				}
			}
			if v.RetailAmount != nil && len(*v.RetailAmount) > 0 {
				if val, err := moneyx.ParseGem(*v.RetailAmount); err != nil {
					logx.Errorw("CreateOrder OrderItem RetailAmount failed to ParseAmount", logx.Field("detail", err.Error()))
				} else {
					orderItem.RetailAmount = uint64(val)
				}
			}
			if v.DiscountAmount != nil && len(*v.DiscountAmount) > 0 {
				if val, err := moneyx.ParseGem(*v.DiscountAmount); err != nil {
					logx.Errorw("CreateOrder OrderItem DiscountAmount failed to ParseAmount", logx.Field("detail", err.Error()))
				} else {
					orderItem.DiscountAmount = uint64(val)
				}
			}
			if v.AdjustAmount != nil && len(*v.AdjustAmount) > 0 {
				if val, err := moneyx.ParseAmount(*v.AdjustAmount); err != nil {
					logx.Errorw("CreateOrder OrderItem AdjustAmount failed to ParseAmount", logx.Field("detail", err.Error()))
				} else {
					orderItem.AdjustAmount = val
				}
			}
			if v.ActualAmount != nil && len(*v.ActualAmount) > 0 {
				if val, err := moneyx.ParseGem(*v.ActualAmount); err != nil {
					logx.Errorw("CreateOrder OrderItem ActualAmount failed to ParseAmount", logx.Field("detail", err.Error()))
				} else {
					orderItem.ActualAmount = uint64(val)
				}
			}
			rel.Items = append(rel.Items, &orderItem)
		}
	}
	if len(in.Addresses) > 0 {
		for _, v := range in.Addresses {
			var orderAddress model.OrderAddress
			if v.UserId != nil && *v.UserId > 0 {
				orderAddress.UserID = *v.UserId
			}
			if v.Consignee != nil && len(*v.Consignee) > 0 {
				orderAddress.Consignee = *v.Consignee
			}
			if v.Mobile != nil && len(*v.Mobile) > 0 {
				orderAddress.Mobile = *v.Mobile
			}
			if v.Province != nil && len(*v.Province) > 0 {
				orderAddress.Province = *v.Province
			}
			if v.City != nil && len(*v.City) > 0 {
				orderAddress.City = *v.City
			}
			if v.District != nil && len(*v.District) > 0 {
				orderAddress.District = *v.District
			}
			if v.Street != nil && len(*v.Street) > 0 {
				orderAddress.Street = *v.Street
			}
			if v.Address != nil && len(*v.Address) > 0 {
				orderAddress.DetailedAddress = *v.Address
			}
			if v.PostalCode != nil && len(*v.PostalCode) > 0 {
				orderAddress.PostalCode = *v.PostalCode
			}
			if v.RegionCode != nil && len(*v.RegionCode) > 0 {
				orderAddress.RegionCode = *v.RegionCode
			}
			if v.Label != nil && len(*v.Label) > 0 {
				orderAddress.Label = *v.Label
			}
			orderAddress.Status = uint8(globalkey.StatusEnabled)
			rel.Addresses = append(rel.Addresses, &orderAddress)
		}
	}
	if len(in.Adjustments) > 0 {
		for _, v := range in.Adjustments {
			var orderAdjustment model.OrderAdjustment
			if v.Amount != nil && len(*v.Amount) > 0 {
				if val, err := moneyx.ParseAmount(*v.Amount); err != nil {
					logx.Errorw("CreateOrder orderAdjustment Amount failed to ParseAmount", logx.Field("detail", err.Error()))
				} else {
					orderAdjustment.Amount = val
				}
			}
			if v.Memo != nil && len(*v.Memo) > 0 {
				orderAdjustment.Memo = *v.Memo
			}
			orderAdjustment.Status = uint8(globalkey.StatusEnabled)
			if v.OperatedBy != nil && *v.OperatedBy > 0 {
				orderAdjustment.OperatedBy = *v.OperatedBy
			}
			orderAdjustment.OperatedAt = null.TimeFrom(now)
			rel.Adjustments = append(rel.Adjustments, &orderAdjustment)
		}
	}
	if len(in.Promotions) > 0 {
		for _, v := range in.Promotions {
			var orderDiscount model.OrderDiscount
			if v.SkuId != nil && *v.SkuId > 0 {
				orderDiscount.SkuID = *v.SkuId
			}
			if v.ProductId != nil && *v.ProductId > 0 {
				orderDiscount.ProductID = *v.ProductId
			}
			if v.Title != nil && len(*v.Title) > 0 {
				orderDiscount.Title = *v.Title
			}
			if v.Slug != nil && len(*v.Slug) > 0 {
				orderDiscount.Slug = *v.Slug
			}
			if v.ActivityId != nil && *v.ActivityId > 0 {
				orderDiscount.ActivityID = *v.ActivityId
			}
			if v.ActivityRuleId != nil && *v.ActivityRuleId > 0 {
				orderDiscount.ActivityRuleID = *v.ActivityRuleId
			}
			if v.CouponTemplateId != nil && *v.CouponTemplateId > 0 {
				orderDiscount.CouponTemplateID = *v.CouponTemplateId
			}
			if v.CouponId != nil && *v.CouponId > 0 {
				orderDiscount.CouponID = *v.CouponId
			}
			if v.GrouponAmount != nil && len(*v.GrouponAmount) > 0 {
				if val, err := moneyx.ParseAmount(*v.GrouponAmount); err != nil {
					logx.Errorw("CreateOrder orderDiscount GrouponAmount failed to ParseAmount", logx.Field("detail", err.Error()))
				} else {
					orderDiscount.GrouponAmount = uint64(val)
				}
			}
			if v.WholesaleAmount != nil && len(*v.WholesaleAmount) > 0 {
				if val, err := moneyx.ParseAmount(*v.WholesaleAmount); err != nil {
					logx.Errorw("CreateOrder orderDiscount WholesaleAmount failed to ParseAmount", logx.Field("detail", err.Error()))
				} else {
					orderDiscount.WholesaleAmount = uint64(val)
				}
			}
			if v.CouponAmount != nil && len(*v.CouponAmount) > 0 {
				if val, err := moneyx.ParseAmount(*v.CouponAmount); err != nil {
					logx.Errorw("CreateOrder orderDiscount CouponAmount failed to ParseAmount", logx.Field("detail", err.Error()))
				} else {
					orderDiscount.CouponAmount = uint64(val)
				}
			}
			if v.ActivityAmount != nil && len(*v.ActivityAmount) > 0 {
				if val, err := moneyx.ParseAmount(*v.ActivityAmount); err != nil {
					logx.Errorw("CreateOrder orderDiscount ActivityAmount failed to ParseAmount", logx.Field("detail", err.Error()))
				} else {
					orderDiscount.ActivityAmount = uint64(val)
				}
			}
			if v.IntegralAmount != nil && len(*v.IntegralAmount) > 0 {
				if val, err := moneyx.ParseAmount(*v.IntegralAmount); err != nil {
					logx.Errorw("CreateOrder orderDiscount IntegralAmount failed to ParseAmount", logx.Field("detail", err.Error()))
				} else {
					orderDiscount.IntegralAmount = uint64(val)
				}
			}
			if v.DiscountAmount != nil && len(*v.DiscountAmount) > 0 {
				if val, err := moneyx.ParseAmount(*v.DiscountAmount); err != nil {
					logx.Errorw("CreateOrder orderDiscount DiscountAmount failed to ParseAmount", logx.Field("detail", err.Error()))
				} else {
					orderDiscount.DiscountAmount = uint64(val)
				}
			}
			if v.Integrals != nil && *v.Integrals > 0 {
				orderDiscount.Integrals = *v.Integrals
			}
			rel.Discounts = append(rel.Discounts, &orderDiscount)
		}
	}
	if len(in.Payments) > 0 {
		for _, v := range in.Payments {
			var orderPayment model.OrderPayment
			if v.No != nil && len(*v.No) > 0 {
				orderPayment.No = *v.No
			}
			if v.Amount != nil && len(*v.Amount) > 0 {
				if val, err := moneyx.ParseAmount(*v.Amount); err != nil {
					logx.Errorw("CreateOrder orderPayment Amount failed to ParseAmount", logx.Field("detail", err.Error()))
				} else {
					orderPayment.Amount = uint64(val)
				}
			}
			if v.Type != nil && *v.Type > 0 {
				orderPayment.Type = uint8(*v.Type)
			}
			if v.Name != nil && len(*v.Name) > 0 {
				orderPayment.Name = *v.Name
			}
			if v.Code != nil && len(*v.Code) > 0 {
				orderPayment.Code = *v.Code
			}
			orderPayment.Status = uint8(tradeState)
			rel.Payments = append(rel.Payments, &orderPayment)
		}
	}
	if len(in.Shipments) > 0 {
		for _, v := range in.Shipments {
			var orderShipment model.OrderShipment
			if v.No != nil && len(*v.No) > 0 {
				orderShipment.No = *v.No
			}
			if v.Type != nil && *v.Type > 0 {
				orderShipment.Type = uint8(*v.Type)
			}
			if v.Name != nil && len(*v.Name) > 0 {
				orderShipment.Name = *v.Name
			}
			if v.Code != nil && len(*v.Code) > 0 {
				orderShipment.Code = *v.Code
			}
			orderShipment.Status = uint8(globalkey.StatusEnabled)
			rel.Shipments = append(rel.Shipments, &orderShipment)
		}
	}

	err = l.svcCtx.Order.Insert(l.ctx, tx, &trade, rel)
	if err != nil {
		tx.Rollback()
		return nil, resultx.StatusError(resultx.ORDER_CREATE_FAILED, "")
	}

	tx.Commit()

	return &order.CreateOrderResp{
		Id: &trade.ID,
	}, nil
}
